/*
 * FengGUI - Java GUIs in OpenGL (http://www.fenggui.org)
 * 
 * Copyright (C) 2005, 2006 FengGUI Project
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details:
 * http://www.gnu.org/copyleft/lesser.html#TOC3
 * 
 * Created on 22.11.2007
 * $Id$
 */
package org.fenggui.binding.render.text.advanced;

import org.fenggui.binding.render.Graphics;
import org.fenggui.binding.render.IOpenGL;
import org.fenggui.util.Dimension;

/**
 * This is a part of the content. This can be anything, Text, Images, URL, ...
 * 
 * <p>
 * Usually this parts are generated by the ContentFactory.
 * </p>
 * 
 * @see IContentFactory
 * 
 * @author marcmenghin, last edited by $Author$, $Date$
 * @version $Revision$
 */
public abstract class AbstractContentPart
{
	private Dimension size = null;
	private boolean selected = false;
	private boolean hovered = false;
	private boolean hideContent = false;

	private int beforeLength = 0;
	private int afterLength = 0;
	private TextStyle style = null;
	
	public AbstractContentPart(int beforeLength, int afterLength, TextStyle style)
	{
		this.beforeLength = beforeLength;
		this.afterLength = afterLength;
		this.style = style;
	}

	/**
	 * Returns True if the content of this Part is breakable. Normally this is true if the
	 * AtomCount is greater than one.
	 * 
	 * @return
	 */
	public abstract boolean isBreakable();

	/**
	 * Breaks a part into two parts. It fill the max. words into the remaining part.
	 * The returned part is everything that didn't fit into the given width. If it is a
	 * firstPart and no word fits into the width it will split the first word on the
	 * character level. 
	 * 
	 * @param width
	 *          The width this part should fit into.
	 * @param onlyPart
	 * 				true if this is the only part in a line.
	 * @return Returns everything that is too much for the given width.
	 */
	public abstract AbstractContentPart splitAtWord(int width, boolean onlyPart);

	/**
	 * Breaks a part into two parts. It fill the max. atoms into the remaining part.
	 * The returned part is everything that didn't fit into the given width.
	 * 
	 * @param width
	 *          The width this part should fit into.
	 * @param onlyPart
	 * 				true if this is the only part in a line.
	 * @return Returns everything that is too much for the given width.
	 */
	public abstract AbstractContentPart splitAtChar(int width);

	/**
	 * Breaks the part into two parts. It fills the max. atoms into the remaining part.
	 * The returned part is everything after the given atom.
	 * 
	 * @param atom atom to cut after
	 * @return Returns everything after the given atom.
	 */
	public abstract AbstractContentPart splitAtAtom(int atom);
	
	/**
	 * Merges two parts where the canMerge() Method returned true.
	 * 
	 * @param part
	 *          part to merge with this.
	 */
	public abstract void mergePart(AbstractContentPart part);

	/**
	 * Checkes if the two parts can be merged or not.
	 * 
	 * @param part
	 * @return
	 */
	public abstract boolean canMerge(AbstractContentPart part);

	/**
	 * Renders this content Parts content to the position.
	 * 
	 * @param x
	 * @param y
	 * @param g
	 * @param gl
	 */
	public abstract void render(int x, int y, Graphics g, IOpenGL gl);

	/**
	 * Returns the amount of Atoms within this content part.
	 * 
	 * @return
	 */
	public abstract int getAtomCount();

	/**
	 * Calculates the position and returns the atom count to this position.
	 * 
	 * @param x
	 *          Position in pixels on screen.
	 * @return Position in atoms within content.
	 */
	public abstract int calculatePositionInAtoms(int x);

	/**
	 * Returns the position of an atom.
	 * 
	 * @param atom
	 *          Position in atoms within this content part.
	 * @return Position in pixels from the content start position (0).
	 */
	public abstract int getActivePosition();

	/**
	 * if this returns true then this part can be removed if an other part is at the
	 * same line. True means that this part is empty and will not display anything.
	 * @return
	 */
	public abstract boolean isEmpty();

	/**
	 * Returns the position of the currently selected atom. Essentially it is a call to
	 * getAtomPosition with the current selected atom as parameter.
	 * 
	 * @return
	 */
	public abstract int getAtomPosition(int atom);

	/**
	 * Returns if this part has an active Atom.
	 *  
	 * @return
	 */
	public abstract boolean hasActiveAtom();

	/**
	 * This is called if the user presses a key on the keyboard.
	 * 
	 * @param c
	 *          the character the pressed key represents.
	 * @return true if something changed, false otherwise.
	 */
	public abstract boolean addChar(char c);

	/**
	 * Adds new content to this part. Usually this is used for pasting
	 * content and similar things.
	 * 
	 * @param content content to add.
	 * @return true if content could be added.
	 */
	public abstract boolean addContent(String content);

	/**
	 * Removes the following char of the current selected position.
	 * 
	 * @return returns the removed char or null if none could be removed.
	 */
	public abstract Character removeNextAtom();

	/**
	 * Removes the character before the current selected position.
	 * 
	 * @return returns the removed char or null if none could be removed.
	 */
	public abstract Character removePreviousAtom();

	/**
	 * Sets the currently selected Atom. Set it to -1 to remove the selection.
	 * 
	 * @param atom
	 */
	public abstract void setActiveAtom(int atom);

	/**
	 * Returns the content of this contentPart in a reproducible form. Creating a new
	 * content part with this String should result in the same content being displayed.
	 * 
	 * @return
	 */
	public abstract String getContent();

	public void setHovered(boolean hovered)
	{
		this.hovered = hovered;
	}

	public boolean isHovered()
	{
		return hovered;
	}

	protected void setSize(Dimension size)
	{
		this.size = size;
	}

	public Dimension getSize()
	{
		return size;
	}

	/**
	 * @return Returns the selected.
	 */
	protected boolean isSelected()
	{
		return selected;
	}

	/**
	 * @param selected
	 *          The selected to set.
	 */
	protected void setSelected(boolean selected)
	{
		this.selected = selected;
	}

	/**
	 * @return the hideContent
	 */
	public boolean isHideContent()
	{
		return hideContent;
	}

	/**
	 * @param hideContent
	 *          the hideContent to set
	 */
	public void setHideContent(boolean hideContent)
	{
		this.hideContent = hideContent;
	}

	/**
	 * @return Returns the beforeLength.
	 */
	public int getBeforeLength()
	{
		return beforeLength;
	}

	/**
	 * @return Returns the afterLength.
	 */
	public int getAfterLength()
	{
		return afterLength;
	}
	
	public int getIndexCount()
	{
		return beforeLength + this.getAtomCount() + afterLength;
	}

	public TextStyle getStyle()
	{
		return style;
	}

	public void setStyle(TextStyle style)
	{
		this.style = style;
	}
}
